﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Data.SqlClient;
using System.Data;
using XLugia.Lib.XDataBase.Base.Lib;
using XLugia.Lib.XDataBase.Base.Model;

namespace XLugia.Lib.XDataBase.Engine.Lib
{
    /// <summary>
    /// 数据库脚本执行控制器
    /// </summary>
    public class Executor : IDisposable
    {
        /// <summary>
        /// 数据库类型
        /// </summary>
        DatabaseConnector.DatabaseTypes databaseType = DatabaseConnector.DatabaseTypes.MSSQL;

        /// <summary>
        /// MSSQL脚本执行控制器
        /// </summary>
        MSSQL.Lib.MSSQLExecutor mssqlDatabaseExecutor;

        /// <summary>
        /// MSSQL脚本执行控制器
        /// </summary>
        MySQL.Lib.MySQLExecutor mysqlDatabaseExecutor;

        /// <summary>
        /// 实例化数据库脚本执行控制器
        /// </summary>
        /// <param name="databaseConnector">数据库连接器。</param>
        public Executor(DatabaseConnector databaseConnector)
        {
            databaseType = databaseConnector.databaseType;
            switch (databaseType)
            {
                case DatabaseConnector.DatabaseTypes.MySQL:
                    mysqlDatabaseExecutor = new MySQL.Lib.MySQLExecutor(databaseConnector);
                    break;
                default:
                    mssqlDatabaseExecutor = new MSSQL.Lib.MSSQLExecutor(databaseConnector);
                    break;
            }
        }

        /// <summary>
        /// 创建一个原始 SQL 查询，该查询将返回给定泛型类型的元素。类型可以是包含与从查询返回的列名匹配的属性的任何类型，也可以是简单的基元类型。
        /// </summary>
        /// <typeparam name="T">指定查询所返回对象的类型。</typeparam>
        /// <param name="scriptModel">一个 DatabaseScriptModel 对象。</param>
        /// <returns>返回查询结果。</returns>
        public T sqlQuery<T>(DatabaseScriptModel scriptModel)
        {
            switch (databaseType)
            {
                case DatabaseConnector.DatabaseTypes.MySQL:
                    return mysqlDatabaseExecutor.sqlQuery<T>(scriptModel);
                default:
                    return mssqlDatabaseExecutor.sqlQuery<T>(scriptModel);
            }
        }

        /// <summary>
        /// 创建一个原始 SQL 查询，该查询将返回给定泛型类型的元素集合。类型可以是包含与从查询返回的列名匹配的属性的任何类型，也可以是简单的基元类型。
        /// </summary>
        /// <typeparam name="T">指定查询所返回对象的类型。</typeparam>
        /// <param name="scriptModel">一个 DatabaseScriptModel 对象。</param>
        /// <returns>返回查询结果集合。</returns>
        public List<T> sqlQueryToList<T>(DatabaseScriptModel scriptModel)
        {
            switch (databaseType)
            {
                case DatabaseConnector.DatabaseTypes.MySQL:
                    return mysqlDatabaseExecutor.sqlQueryToList<T>(scriptModel);
                default:
                    return mssqlDatabaseExecutor.sqlQueryToList<T>(scriptModel);
            }
        }

        /// <summary>
        /// 对数据库执行给定的 DDL/DML 命令。
        /// </summary>
        /// <param name="scriptModel">一个 DatabaseScriptModel 对象。</param>
        public void executeSqlCommand(DatabaseScriptModel scriptModel)
        {
            executeSqlCommand(new List<DatabaseScriptModel> { scriptModel });
        }

        /// <summary>
        /// 对数据库执行给定的 DDL/DML 命令，多个DatabaseScriptModel在一个事务里执行。
        /// </summary>
        /// <param name="scriptModel">一个 List<DatabaseScriptModel> 对象。</param>
        public void executeSqlCommand(List<DatabaseScriptModel> scriptModels)
        {
            switch (databaseType)
            {
                case DatabaseConnector.DatabaseTypes.MySQL:
                    mysqlDatabaseExecutor.executeSqlCommand(scriptModels);
                    break;
                default:
                    mssqlDatabaseExecutor.executeSqlCommand(scriptModels);
                    break;
            }
        }

        /// <summary>
        /// 不使用事务对数据库执行给定的 DDL/DML 命令。
        /// </summary>
        /// <param name="scriptModel">一个 DatabaseScriptModel 对象。</param>
        public void executeSqlCommandWithOutTransaction(DatabaseScriptModel scriptModel)
        {
            executeSqlCommandWithOutTransaction(new List<DatabaseScriptModel> { scriptModel });
        }

        /// <summary>
        /// 不使用事务对数据库执行给定的 DDL/DML 命令集合。
        /// </summary>
        /// <param name="scriptModel">一个 List<DatabaseScriptModel> 对象。</param>
        public void executeSqlCommandWithOutTransaction(List<DatabaseScriptModel> scriptModels)
        {
            switch (databaseType)
            {
                case DatabaseConnector.DatabaseTypes.MySQL:
                    mysqlDatabaseExecutor.executeSqlCommandWithOutTransaction(scriptModels);
                    break;
                default:
                    mssqlDatabaseExecutor.executeSqlCommandWithOutTransaction(scriptModels);
                    break;
            }
        }


        #region 大批量高速数据插入
        /// <summary>
        /// 将DataTable中的数据大批量高速写入至数据库，MySQL目前只支持字符、数字、时间、布尔类型。
        /// </summary>
        /// <param name="sqlDataTable">DataTable数据源</param>
        public void executeBulkSqlCommand(DataTable sqlDataTable)
        {
            switch (databaseType)
            {
                case DatabaseConnector.DatabaseTypes.MySQL:
                    mysqlDatabaseExecutor.executeMySQLBulkSqlCommand(sqlDataTable);
                    break;
                default:
                    mssqlDatabaseExecutor.executeMSSQLBulkSqlCommand(sqlDataTable);
                    break;
            }
        }
        #endregion

        /// <summary>
        /// 资源释放
        /// </summary>
        public void Dispose()
        {
            if (this.mssqlDatabaseExecutor != null)
            {
                this.mssqlDatabaseExecutor.Dispose();
                this.mssqlDatabaseExecutor = null;
            }

            if (this.mysqlDatabaseExecutor != null)
            {
                this.mysqlDatabaseExecutor.Dispose();
                this.mysqlDatabaseExecutor = null;
            }
            
        }
    }
}
